<?php

namespace app\components;

use Yii;
use app\components\Log;
use app\components\BaseController;
use app\models\Tenant;
use yii\web\ServerErrorHttpException;
use app\components\PerformanceLog;

class BaseMemberController extends BaseController
{
    const DEV_OPENID = 'o2Rmrtzjjg68MAirKb8XUJ7YdWc0'; // 仅用于测试

    const DEV_APPID = 'wxeca2e361be1de14c';

    const DEV_WEBFORM = 'https://webform.xgate.com/app/index.php/webforms/form/form?encid=adc94e57-f95b-6fa5-3cff-188eba392065&tracker=350e92b9-5986-4f05-f72c-77289fac5343';

    const CARD_ID = 'p2Rmrt791Amsz44JS-TWpY4X0LwY';
    
    public $defaultAction = 'index';

    public $layout;

    public $openid;

    public $appid;

    public $identifier;

    public function init()
    {
//     	PerformanceLog::begin();
        // 完全采用跟产品一样的方式进行开发
        $this->bootstrapPROD();
    }

    // 线上环境初始化方法
    public function bootstrapPROD()
    {
//         Log::debug('BOOTSTRAP MEMBER START');
        // 必须拿到appid，如果是走OAuth就不用GET
        $appid = $this->getAppid();
        if (empty($appid)) {
            if (empty($_GET['appid'])) {
                throw new ServerErrorHttpException('用户信息过期，请重新登录。');
            } else {
                $this->setAppid($_GET['appid']);
            }
        }
        $this->appid = $appid;
        Log::debug('BOOTSTRAP.1 APPID', $this->appid);
        // 获取identifier，然后做前端的区分
        $identifier = $this->getIdentifier();
        if (empty($identifier)) {
            $identifier = Tenant::find()->select('identifier')->where(['appid' => $appid])->scalar();
            if (empty($identifier)) {
                throw new ServerErrorHttpException('BOOTSTRAP FAILED, IDENTIFIER NOT FOUND');
            } else {
                $this->setIdentifier($identifier);
            }
        }
        $this->identifier = $identifier;
        Log::debug('BOOTSTRAP.2 IDENTIFIER', $this->identifier);
        
        // 使用不同的前端Layout
        if (file_exists(Yii::$app->basePath . '/views/layouts/' . $identifier . '.php')) {
            $this->layout = $identifier;
            Log::debug('BOOTSTRAP.3 LAYOUT', Yii::$app->basePath . '/views/layouts/' . $identifier . '.php');
        } else {
            throw new ServerErrorHttpException('BOOTSTRAP FAILED, LAYOUT NOT FOUND');
        }
        
        // 必须拿到openid，如果是走OAuth就不用GET
        $userInfo = $this->getUserInfo(); 
        Log::debug('BOOTSTRAP.3-1 User Info', $userInfo);
        if (empty($userInfo)) {        	
            // 如果openid存在
            $openid = $this->getOpenid();
            if (empty($openid)) {            	
                if (empty($_GET['openid'])) {                	
                    throw new ServerErrorHttpException('BOOTSTRAP FAILED, OPENID NOT FOUND');
                } else {                	
                    $openid = $_GET['openid'];
                    $this->setOpenid($openid);
                }
            } else {            	
                $this->setOpenid($openid);
            }
        } else {        	
            $openid = $this->getOpenid();
        }
        $this->openid = $openid;
        Log::debug('BOOTSTRAP.4 OPENID', $this->openid);

//         Log::debug('BOOTSTRAP MEMBER END');
    }

    // 开发环境下初始化方法
    // public function bootstrapDEV()
    // {
    //     $appid = $this->getAppid();
    //     if (!$appid) {
    //         $appid = self::DEV_APPID;
    //         $this->setAppid($appid);
    //     }
    //     $this->appid = $appid;
    //     Log::debug('DEV $this->appid', $this->appid);

    //     $identifier = $this->getIdentifier();
    //     if (!$identifier) {
    //         $tenant = Tenant::find()->where(['appid' => $appid])->one();
    //         if ($tenant) {
    //             $identifier = isset($tenant->identifier) ? $tenant->identifier : false;
    //             if (empty($identifier)) {
    //                 throw new ServerErrorHttpException('BOOTSTRAP FAILED, IDENTIFIER NOT FOUND');
    //             }
    //             $this->setIdentifier($identifier);
    //         } else {
    //             throw new ServerErrorHttpException('BOOTSTRAP FAILED, TENANT NOT FOUND');
    //         }
    //     }
    //     $this->identifier = $identifier;
    //     Log::debug('DEV $this->identifier', $this->identifier);

    //     if (file_exists(Yii::$app->basePath . '/views/layouts/' . $identifier . '.php')) {
    //         $this->layout = $identifier;
    //     } else {
    //         throw new ServerErrorHttpException('BOOTSTRAP FAILED, IDENTIFIER LAYOUT NOT FOUND');
    //     }

    //     $userInfo = $this->getUserInfo();
    //     if (!$userInfo) {
    //         $openid = $this->getOpenid();
    //         if (!$openid) {
    //             $openid = self::DEV_OPENID;
    //             $this->setOpenid($openid);
    //         }
    //     } else {
    //         $openid = $this->getOpenid();
    //     }
    //     $this->openid = $openid;
    //     Log::debug('DEV $this->openid', $this->openid);
    // }

    // 改造的Multiple-Tenant下的createAction
    /**
     * Creates an action based on the given action ID.
     * The method first checks if the action ID has been declared in [[actions()]]. If so,
     * it will use the configuration declared there to create the action object.
     * If not, it will look for a controller method whose name is in the format of `actionXyz`
     * where `Xyz` stands for the action ID. If found, an [[InlineAction]] representing that
     * method will be created and returned.
     * @param string $id the action ID.
     * @return Action|null the newly created action instance. Null if the ID doesn't resolve into any action.
     */
    public function createAction($id)
    {
        if ($id === '') {
            $id = $this->defaultAction;
        }

        $actionMap = $this->actions();
        if (isset($actionMap[$id])) {
            return Yii::createObject($actionMap[$id], [$id, $this]);
        } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) {
            $methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id))));
            // ------ multiple-action ------
            if ($this->identifier) {
                $methodName = $methodName . ucfirst($this->identifier);
            }
            // ------ multiple-action ------
            if (method_exists($this, $methodName)) {
                $method = new \ReflectionMethod($this, $methodName);
                if ($method->isPublic() && $method->getName() === $methodName) {
                    return new \yii\base\InlineAction($id, $this, $methodName);
                }
            }
        }

        return null;
    }

    // 改造的Multiple-Tenant下的render
    /**
     * Renders a view and applies layout if available.
     *
     * The view to be rendered can be specified in one of the following formats:
     *
     * - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
     * - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
     *   The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
     * - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
     *   The actual view file will be looked for under the [[Module::viewPath|view path]] of [[module]].
     * - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]].
     *
     * To determine which layout should be applied, the following two steps are conducted:
     *
     * 1. In the first step, it determines the layout name and the context module:
     *
     * - If [[layout]] is specified as a string, use it as the layout name and [[module]] as the context module;
     * - If [[layout]] is null, search through all ancestor modules of this controller and find the first
     *   module whose [[Module::layout|layout]] is not null. The layout and the corresponding module
     *   are used as the layout name and the context module, respectively. If such a module is not found
     *   or the corresponding layout is not a string, it will return false, meaning no applicable layout.
     *
     * 2. In the second step, it determines the actual layout file according to the previously found layout name
     *    and context module. The layout name can be:
     *
     * - a [path alias](guide:concept-aliases) (e.g. "@app/views/layouts/main");
     * - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
     *   looked for under the [[Application::layoutPath|layout path]] of the application;
     * - a relative path (e.g. "main"): the actual layout file will be looked for under the
     *   [[Module::layoutPath|layout path]] of the context module.
     *
     * If the layout name does not contain a file extension, it will use the default one `.php`.
     *
     * @param string $view the view name.
     * @param array $params the parameters (name-value pairs) that should be made available in the view.
     * These parameters will not be available in the layout.
     * @return string the rendering result.
     * @throws InvalidParamException if the view file or the layout file does not exist.
     */
    public function render($view, $params = [])
    {
        // ------ multiple-view ------
        $view = $this->identifier . '/' . $view;
        // ------ multiple-view ------
        $content = $this->getView()->render($view, $params, $this);
        return $this->renderContent($content);
    }
}
